<?php

namespace app\common;

use Exception;
use support\Request;
use Kingbes\Attribute\Annotation;
use app\model\Menu;
use think\facade\Db;

class Tool
{
    /**
     * 查询 function
     *
     * @param object|string $model 模块
     * @param array $param 参数
     * @return object
     */
    public static function search(object|string $model, array $param = []): object
    {
        return $model::where(function ($query) use ($param) {
            if (isset($param["where"])) {
                $query->where($param["where"]);
            }
            if (isset($param["order"])) {
                $query->order($param["order"]);
            }
            if (isset($param["field"])) {
                $query->field($param["field"]);
            }
        });
    }

    /**
     * 上传文件 function
     *
     * @param Request $request
     * @param string $relative_dir 路径
     * @return array
     */
    public static function uploads(Request $request, string $relative_dir): array
    {
        $relative_dir = ltrim($relative_dir, '/');
        $file = current($request->file());
        if (!$file || !$file->isValid()) {
            throw new Exception('未找到上传文件', 400);
        }
        $full_dir = public_path() . "/" . $relative_dir;
        if (!is_dir($full_dir)) {
            mkdir($full_dir, 0777, true);
        }
        $ext = $file->getUploadExtension() ?: "";
        $mime_type = $file->getUploadMimeType();
        $file_name = $file->getUploadName();
        $file_size = $file->getSize();

        $ext = strtolower($ext);
        $ext_forbidden_map = ['php', 'php3', 'php5', 'css', 'js', 'html', 'htm', 'asp', 'jsp'];
        if (in_array($ext, $ext_forbidden_map)) {
            throw new Exception('不支持该格式的文件上传', 400);
        }
        $relative_path = "/" .  $relative_dir . '/' . bin2hex(pack('Nn', time(), random_int(1, 65535))) . ".$ext";
        $full_path = public_path() . "/" . $relative_path;
        $file->move($full_path);
        return [
            'url'     => "$relative_path",
            'name'     => $file_name,
            'realpath' => $full_path,
            'file_size'     => $file_size,
            'mime_type' => $mime_type,
            'ext' => $ext,
        ];
    }

    /**
     * 获取pdo连接 function
     *
     * @param string $host
     * @param string $username
     * @param string $password
     * @param int $port
     * @param string|null $database
     * @return \PDO
     */
    public static function getPdo($host, $username, $password, $port, $database = null): \PDO
    {
        $dsn = "mysql:host=$host;port=$port;";
        if ($database) {
            $dsn .= "dbname=$database";
        }
        $params = [
            \PDO::MYSQL_ATTR_INIT_COMMAND => "set names utf8mb4",
            \PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
            \PDO::ATTR_EMULATE_PREPARES => false,
            \PDO::ATTR_TIMEOUT => 5,
            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
        ];
        return new \PDO($dsn, $username, $password, $params);
    }

    /**
     * 去除sql文件中的注释 function
     *
     * @param string $str
     * @return string
     */
    public static function removeComments(string $str): string
    {
        return preg_replace("/(\n--[^\n]*)/", "", $str);
    }

    /**
     * 鉴定权限 function
     *
     * @param mixed $Admin
     * @param mixed $route
     * @return boolean
     */
    public static function isRole(mixed $Admin, mixed $route): bool
    {
        $Callback = $route->getCallback();
        $attr = (new \ReflectionMethod($Callback[0], $Callback[1]))
            ->getAttributes(Annotation::class);
        $res = true;
        if (count($attr) > 0) {
            $Auth = $attr[0]->newInstance()->get()["auth"];
            if ($Auth) {
                if (trim($Admin->rules) != "all") {
                    if (!in_array($route->getName(), explode(",", trim($Admin->rules)))) {
                        $res = false;
                    }
                }
            }
        }
        return $res;
    }

    /**
     * 获取菜单栏 function
     *
     * @param mixed $Admin
     * @return array
     */
    public static function getMenu(mixed $Admin): array
    {
        $Menu = Menu::where("type", "in", ["菜单", "目录"])
            ->where(function ($query) use ($Admin) {
                if (trim($Admin->rules) != "all") {
                    $arr = explode(",", trim($Admin->rules));
                    $arr[] = "";
                    $query->where("route", "in", $arr);
                }
            })
            ->order("weight", "desc")
            ->select()
            ->each(function ($v, $k) use ($Admin) {
                // 格式处理
                if ($v["type"] == "菜单") {
                    $v["type"] = 1;
                } else {
                    $v["type"] = 0;
                }
                $v["href"] = route($v["route"]);
                $v["icon"] = "layui-icon " . $v["icon"];
            })
            ->toArray();

        return $Menu;
    }

    /**
     * 获取某个composer包的版本
     * @param string $package
     * @return mixed|string
     */
    public static function getPackageVersion(string $package)
    {
        $installed_php = base_path('vendor/composer/installed.php');
        if (is_file($installed_php)) {
            $packages = include $installed_php;
        }
        return substr($packages['versions'][$package]['version'] ?? 'unknown  ', 0, -2);
    }

    /**
     * 创建数据表 function
     *
     * @param array $data
     * @return string
     */
    public static function createTable(array $data): string
    {
        $field = "";
        foreach ($data["data"]["field_name"] as $k => $v) {
            $field_length = $data["data"]["field_length"][$k] != "" ? "(" . $data["data"]["field_length"][$k] . ")" : "";
            $field_default = $field_length != "" ? "DEFAULT '" . $data["data"]["field_default"][$k] . "'" : "";
            $field .= "`$v` " .
                $data["data"]["field_type"][$k] .
                $field_length . " NOT NULL " .
                $field_default . " COMMENT '" .
                $data["data"]["field_comment"][$k] . "',";
        }
        $key = "";
        if (isset($data["data"]["index"]) && count($data["data"]["index"]) > 0) {
            $key .= ",";
            foreach ($data["data"]["index"]["index_name"] as $k => $v) {
                $index_type = $data["data"]["index"]["index_type"][$k] == "normal" ? "" : "UNIQUE ";
                $index_fields = self::index_fields($data["data"]["index"]["index_fields"][$k]);
                $key .= "$index_type" . "KEY `" . $v . "` ($index_fields),";
            }
        }
        $sql = sprintf(
            "CREATE TABLE `%s` (
            `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
            %s
            `create_time` int unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
            `update_time` int unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
            PRIMARY KEY (`id`) USING BTREE%s
          ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC COMMENT='%s';",
            $data["table"],
            $field,
            $key,
            $data["COMMENT"]
        );
        return $sql;
    }

    /**
     * 获取表信息sql function
     *
     * @param string $table
     * @return string
     */
    public static function getTable(string $table): string
    {
        $TABLE_SCHEMA = config("thinkorm.connections.mysql.database");
        $sql = sprintf("SELECT TABLE_NAME, ENGINE, TABLE_COMMENT, AUTO_INCREMENT
        FROM INFORMATION_SCHEMA.TABLES
        WHERE TABLE_SCHEMA = '%s' AND TABLE_NAME = '%s';", $TABLE_SCHEMA, $table);
        return $sql;
    }

    /**
     * 索引字段格式化 function
     *
     * @param string $str
     * @return string
     */
    private static function index_fields(string $str): string
    {
        $arr = explode(",", $str);
        foreach ($arr as $k => $v) {
            $arr[$k] = "`$v`";
        }

        return implode(",", $arr);
    }
}
